/**
* @brief
*		Find errors and decrease probability of getting errors of the same kind in the future
*		This piece of code won't compile and it doesn't describe an entire algorithm: just part of some page storage
*
* @author
*		AnnaM
*/

#include <Windows.h>
#include <stdio.h>

enum PAGE_COLOR
{ // !!! start count from 0, to coincide with index in PageStrg[]
	PG_COLOR_GREEN = 0, /* page may be released without high overhead */
	PG_COLOR_YELLOW, /* nice to have */
	PG_COLOR_RED	/* page is actively used */
};


/**
* UINT Key of a page in hash-table (prepared from color and address)
*/
union PageKey
{
	struct
	{
		CHAR	cColor : 8;
		UINT	cAddr : 24;
	};

	UINT	uKey;
};


/* Prepare from 2 chars the key of the same configuration as in PageKey */
//#define CALC_PAGE_KEY( Addr, Color )	(  (Color) + (Addr) << 8 )    !!! + goes before <<
#define CALC_PAGE_KEY( Addr, Color )	(  (Color) + ((int)Addr << 8) ) //!!! make void* an int first

/**
* Descriptor of a single guest physical page
*/
struct PageDesc
{
	PageKey			uKey;

	/* list support */
	PageDesc		*next, *prev;
};

//!!! (Desc).uKey.uKey from (Desc).uKey, !!!made it in one line without {}
#define PAGE_INIT(Desc, Addr, Color)  (Desc).uKey.uKey = CALC_PAGE_KEY(Addr, Color), (Desc).next = (Desc).prev = NULL


/* storage for pages of all colors */
static PageDesc* PageStrg[3];

void PageStrgInit()
{
	memset(PageStrg, 0, 3*sizeof(*PageStrg));// !!!, !!! memset(PageStrg, 0, sizeof(&PageStrg));
}

PageDesc* PageFind(void* ptr, char color)
{
	for (PageDesc* Pg = PageStrg[color]; Pg; Pg = Pg->next){       //  for(...);... !!!
		if (Pg->uKey.uKey == CALC_PAGE_KEY(ptr, color))				// !!! Pg->uKey.uKey instead of Pg->uKey
			return Pg;
	}
	return NULL;
}


void PageRemove(PageDesc* Pg){};//!!!? used, but was absent

PageDesc* PageReclaim(UINT cnt)
{
	UINT color = 0;
	PageDesc* Pg = PageStrg[color]; //!!! initialization added
	while (cnt)
	{    
		if (Pg){                               // !!! check wasn't here
			Pg = Pg->next;
			PageRemove(PageStrg[color]);
			cnt--;
		} else if (color < 2){
			color++;
			Pg = PageStrg[color];
		}
		else {
			return NULL;   //!!! this case is added
		}
	}
	return Pg; //!!! return added
}



PageDesc* PageInit(void* ptr, UINT color)
{
	PageDesc* pg = new PageDesc;
	if (pg)
		PAGE_INIT(*pg, ptr, color);//!!! *pg instead of &pg; !!! ';' before else   TODO
	else
		printf("Allocation has failed\n");
	return pg;
}

/**
* Print all mapped pages
*/
void PageDump()
{
	
#define PG_COLOR_NAME(clr) #clr
	char* PgColorName[] =    //!!! wrong order of colors
	{
		PG_COLOR_NAME(PG_COLOR_GREEN),
		PG_COLOR_NAME(PG_COLOR_YELLOW),
		PG_COLOR_NAME(PG_COLOR_RED)
		
	};

	UINT color = 0;
	for (UINT color = 0; color <= PG_COLOR_RED; color++)
	{
		printf("PgStrg[(%s) %u] ********** \n", color, PgColorName[color]);
		for (PageDesc* Pg = PageStrg[color]; Pg != NULL; Pg = Pg->next) // !!! it was ++color
		{
			if (Pg->uKey.cAddr = NULL) //!!! Pg->uAddr changed to Pg->uKey.cAddr
				continue;

			printf("Pg :Key = 0x%x, addr %x\n", Pg->uKey.uKey, Pg->uKey.cAddr);//!!! Pg->uKey.uKey instead of Pg->uKey; !!! Pg->uAddr changed to Pg->uKey.cAddr; !!! addr %p changed to addr %x
		}
	}
#undef PG_COLOR_NAME
}